package cn.fivestars.springcloud.payment.serivce.impl;

import cn.fivestars.springcloud.commons.entities.Payment;
import cn.fivestars.springcloud.payment.dao.PaymentDao;
import cn.fivestars.springcloud.payment.serivce.PaymentService;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author liangchenzhou1024@163.com
 * @date 2021/2/1
 */
@Service
public class PaymentServiceImpl implements PaymentService {
    private static final Logger logger = LoggerFactory.getLogger(PaymentServiceImpl.class);

    @Resource
    private PaymentDao paymentDao;

    @Override
    public int insert(Payment payment) {
        return paymentDao.insert(payment);
    }

    @Override
    public int insertTimeOut(Payment payment) {
        int timeout = 3;
        long start = System.currentTimeMillis();
        try {
            TimeUnit.SECONDS.sleep(timeout);
            return paymentDao.insert(payment);
        } catch (InterruptedException e) {
            logger.error("timeout:{}ms, e:", System.currentTimeMillis() - start, e);
        }
        return 0;
    }

    @Override
    public int error(Payment payment) {
        return -1;
    }

    @Override
    public Payment selectById(Long id) {
        return paymentDao.selectById(id);
    }

    @Override
    @HystrixCommand(fallbackMethod = "handleTimeOutOfSelectByIdTimeout",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "4000")
            })
    public Payment selectByIdTimeout(Long id) {
        //int age = 10/0;

        try {
            TimeUnit.SECONDS.sleep(5);
            return paymentDao.selectById(id);
        } catch (InterruptedException e) {
            logger.error("timeout, error:", e);
        }
        return null;
    }

    @Override
    public Payment handleTimeOutOfSelectByIdTimeout(Long id) {
        logger.warn("fallback:handleTimeOutOfSelectByIdTimeout:id={}", id);
        return new Payment(-1L, "-1");
    }

    // ================= 服务熔断 =====================
    @HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback",
            commandProperties = {
                    @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 是否开启断路器
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求次数
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") // 失败率达到多少后跳闸
            })
    @Override
    public Payment paymentCircuitBreaker(Long id) {

        if (id < 0) {
            throw new RuntimeException("id should not be plural");
        }

        return new Payment(id, IdUtil.fastSimpleUUID());
    }

    @Override
    public Payment paymentCircuitBreakerFallback(Long id) {
        logger.warn("fallback paymentCircuitBreaker, id={}", id);
        return null;
    }
}
